#include "MYQPNGImageWriter.h"
#include <png.h>
#include  <pngconf.h>
#include <pnglibconf.h>
#include <pngpriv.h>
#include <pngstruct.h>
#include <pngdebug.h>
#include <QFile>
#include <QPoint>
#include <QImage>
#include <QDataStream>
#include <QPicture>
#include <QPainter>
#include <iostream>
  #include   <string.h>
#include <qiodevice.h>
#include <qimage.h>
#include <qDebug>
#include <osg/Endian>


using namespace osg;
static void qt_png_warning(png_structp /*png_ptr*/, png_const_charp message)
{
    qWarning("libpng warning: %s", message);
}
static void  qpiw_flush_fn(png_structp /* png_ptr */)
{
}

static void  qpiw_write_fn(png_structp png_ptr, png_bytep data, png_size_t length)
{
    MYQPNGImageWriter* qpiw = (MYQPNGImageWriter*)png_get_io_ptr(png_ptr);
    QIODevice* out = qpiw->device();
    uint nr = out->write((char*)data, length);
    if (nr != length) {
        png_error(png_ptr, "Write Error");
        return;
    }
}

static void set_text(const QImage &image, png_structp png_ptr, png_infop info_ptr,
                     const QString &description)
{
}

enum DisposalMethod { Unspecified, NoDisposal, RestoreBackground, RestoreImage };



MYQPNGImageWriter::MYQPNGImageWriter()
{
    dev =NULL;
}

MYQPNGImageWriter::~MYQPNGImageWriter()
{
    dev->close();
    delete dev;
    dev =NULL;
}
bool MYQPNGImageWriter::writeImage(osg::Image *img)
{
    png_structp png = NULL;
    png_infop   info = NULL;
    int color;
    int bitDepth;
    png_bytep *rows = NULL;

    //Create write structure
    png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if(!png) return false;

    //Create infr structure
    info = png_create_info_struct(png);
    if(!info) {
        png_destroy_write_struct(&png, 0);
        return false;
    }
    if (setjmp(png_jmpbuf(png))) {
        png_destroy_write_struct(&png, &info);
        return false;
    }
  //Set custom write function so it will write to ostream
    png_set_write_fn(png, (void*)this, qpiw_write_fn, qpiw_flush_fn);

//    png_set_write_fn(png,&fout,png_write_ostream,png_flush_ostream);

    //Set compression level  compression_level
    png_set_compression_level(png, 9);

    switch(img->getPixelFormat()) {
        case(GL_DEPTH_COMPONENT): color = PNG_COLOR_TYPE_GRAY; break;
        case(GL_LUMINANCE): color = PNG_COLOR_TYPE_GRAY; break;
        case(GL_ALPHA): color = PNG_COLOR_TYPE_GRAY; break; //Couldn't find a color type for pure alpha, using gray instead
        case(GL_LUMINANCE_ALPHA): color = PNG_COLOR_TYPE_GRAY_ALPHA ; break;
        case(GL_RGB): color = PNG_COLOR_TYPE_RGB; break;
        case(GL_RGBA): color = PNG_COLOR_TYPE_RGB_ALPHA; break;
        case(GL_BGR): color = PNG_COLOR_TYPE_RGB; png_set_bgr(png); break;
        case(GL_BGRA): color = PNG_COLOR_TYPE_RGB_ALPHA; png_set_bgr(png); break;
        default: return false; break;
    }

    //wish there was a Image::computeComponentSizeInBits()
    unsigned int numComponents = osg::Image::computeNumComponents(img->getPixelFormat());
    bitDepth = (numComponents>0) ? (osg::Image::computePixelSizeInBits(img->getPixelFormat(),img->getDataType())/numComponents) : 0;
    if(bitDepth!=8 && bitDepth!=16) return false;

    //Create row data
    rows = new png_bytep[img->t()];
    for(int i = 0; i < img->t(); ++i) {
        rows[i] = (png_bytep)img->data(0,img->t() - i - 1);
    }

    //Write header info
    png_set_IHDR(png, info, img->s(), img->t(),
                bitDepth, color, PNG_INTERLACE_NONE,
                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);


    png_write_info(png, info);

    //must take place after png_write_info: png_set_swap verifies 16bit depth before setting transformation flag.
    if(bitDepth > 8 && getCpuByteOrder()==LittleEndian) png_set_swap(png);

    //Write data
    png_write_image(png, rows);

    //End write
    png_write_end(png, NULL);

    //Cleanup
    png_destroy_write_struct(&png,&info);
    delete [] rows;
    rows =NULL;
    return true;
}




void MYQPNGImageWriter::setDevice(QIODevice *device)
{
   dev =NULL;
   dev = device;
}


